home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-12-08 | 43.6 KB | 1,528 lines | [TEXT/R*ch] |
- C.S.M.P. Digest Thu, 15 Oct 92 Volume 1 : Issue 183
-
- Today's Topics:
-
- Repeated GetCIcon/PlotCIcon calls
- Powerbook Battery Question
- Quick TCL gDesktop question
- Smooth Animation
- Using PostHighLevelEvents to send low level (KeyPressed) events
- Radio buttons
- menubar in dialogs
-
-
-
- The Comp.Sys.Mac.Programmer Digest is moderated by Michael A. Kelly.
-
- The digest is a collection of article threads from the internet newsgroup
- comp.sys.mac.programmer. It is designed for people who read c.s.m.p. semi-
- regularly and want an archive of the discussions. If you don't know what a
- newsgroup is, you probably don't have access to it. Ask your systems
- administrator(s) for details. (This means you can't post questions to the
- digest.)
-
- Each issue of the digest contains one or more sets of articles (called
- threads), with each set corresponding to a 'discussion' of a particular
- subject. The articles are not edited; all articles included in this digest
- are in their original posted form (as received by our news server at
- cs.uoregon.edu). Article threads are not added to the digest until the last
- article added to the thread is at least one month old (this is to ensure that
- the thread is dead before adding it to the digest). Article threads that
- consist of only one message are generally not included in the digest.
-
- The entire digest is available for anonymous ftp from ftp.cs.uoregon.edu
- [128.223.8.8] in the directory /pub/mac/csmp-digest. Be sure to read the
- file /pub/mac/csmp-digest/README before downloading any files. The most
- recent issues are available from sumex-aim.stanford.edu [36.44.0.6] in the
- directory /info-mac/digest/csmp. If you don't have ftp capability, the sumex
- archive has a mail server; send a message with the text '$MACarch help' (no
- quotes) to LISTSERV@ricevm1.rice.edu for more information.
-
- The digest is also available via email. Just send a note saying that you
- want to be on the digest mailing list to mkelly@cs.uoregon.edu, and you will
- automatically receive each new issue as it is created. Sorry, back issues
- are not available through the mailing list.
-
- Send administrative mail to mkelly@cs.uoregon.edu.
-
-
- -------------------------------------------------------
-
- From: bagpipe@reed.edu!bagpipe.reed.edu!pcalahan (Patrick John Calahan)
- Subject: Repeated GetCIcon/PlotCIcon calls
- Date: 14 Jul 92 22:48:21 GMT
- Organization: Reed College, Portland, OR
-
- I need to plot a fairly large number of color icons a very large number
- of times in my application.
-
- IMV says that you shouldn't call PlotCICon before each GetCIcon because
- it overhead will build up in the resource map. Makes sense to me...that
- seems to be happenening when my system crashes after plotting some number
- of icons...
-
- I don't know what I should be doing to dispose of the data when I'm done
- plotting it. I've tried DisposCIcon & ReleaseResource, and both together,
- but nothing seems to do much good...memory still gets filled up.
-
- I just want to get rid of the things after I draw them...what do I do?
-
- +++++++++++++++++++++++++++
-
- From: mxmora@unix.SRI.COM (Matt Mora)
- Date: 15 Jul 92 15:48:56 GMT
- Organization: SRI International, Menlo Park, California
-
- In article <m0m7vfN-000FO0C@bagpipe.reed.edu> bagpipe@reed.edu!bagpipe.reed.edu!pcalahan (Patrick John Calahan) writes:
-
- >IMV says that you shouldn't call PlotCICon before each GetCIcon because
- >it overhead will build up in the resource map. Makes sense to me...that
- >seems to be happenening when my system crashes after plotting some number
- >of icons...
-
- >I don't know what I should be doing to dispose of the data when I'm done
- >plotting it. I've tried DisposCIcon & ReleaseResource, and both together,
- >but nothing seems to do much good...memory still gets filled up.
-
- >I just want to get rid of the things after I draw them...what do I do?
-
- You could mark them purgeable. But I don't think that really works. I think
- there is a bug with cicns or something because I tried to get rid of the
- memory but it would still fill up the heap. I'm using ploticonid now
- (tech note #30x) and it works fine.
-
- What you might want to do is create a gworld and plot all the icons at
- once. Then blit them in via copybits as you need them. Depending on the
- amount of icons and pixdepth this might not be posible in your case.
-
- Matt
-
-
-
- - --
- ___________________________________________________________
- Matthew Mora | my Mac Matt_Mora@sri.com
- SRI International | my unix mxmora@unix.sri.com
- ___________________________________________________________
-
- +++++++++++++++++++++++++++
-
- From: ozma@kuhub.cc.ukans.edu
- Date: 16 Jul 92 23:41:46 CDT
- Organization: University of Kansas Academic Computing Services
-
- In article <36915@unix.SRI.COM>, mxmora@unix.SRI.COM (Matt Mora) writes:
- > In article <m0m7vfN-000FO0C@bagpipe.reed.edu> bagpipe@reed.edu!bagpipe.reed.edu!pcalahan (Patrick John Calahan) writes:
- >
- >>IMV says that you shouldn't call PlotCICon before each GetCIcon because
- >>it overhead will build up in the resource map. Makes sense to me...that
- >>seems to be happenening when my system crashes after plotting some number
- >>of icons...
-
- > You could mark them purgeable. But I don't think that really works. I think
- > there is a bug with cicns or something because I tried to get rid of the
- > memory but it would still fill up the heap. I'm using ploticonid now
- > (tech note #30x) and it works fine.
-
- I believe ReleaseResource() after every PlotCIcon will do the trick.
-
- john calhoun-
-
-
- +++++++++++++++++++++++++++
-
- From: gluttony@reed.edu!gluttony.reed.edu!pcalahan (Patrick John Calahan)
- Date: 17 Jul 92 21:14:24 GMT
- Organization: Reed College, Portland, OR
-
- In article <1992Jul16.234146.41639@kuhub.cc.ukans.edu>
- ozma@kuhub.cc.ukans.edu writes:
-
- >
- > I believe ReleaseResource() after every PlotCIcon will do the trick.
- >
- > john calhoun-
-
- nope. like i said in the message, i had been using release resource but
- it still wasn't working. i kludged my way around it by quitting the
- application after plotting a lot of icons (i only needed to see them for a
- while while the app is in development). a more elegant solution remains
- a mystery to me
-
- +++++++++++++++++++++++++++
-
- From: ozma@kuhub.cc.ukans.edu
- Date: 19 Jul 92 01:04:03 CDT
- Organization: University of Kansas Academic Computing Services
-
- In article <m0m8zd3-0006ChC@gluttony.reed.edu>, gluttony@reed.edu!gluttony.reed.edu!pcalahan (Patrick John Calahan) writes:
- > In article <1992Jul16.234146.41639@kuhub.cc.ukans.edu>
- > ozma@kuhub.cc.ukans.edu writes:
- >> I believe ReleaseResource() after every PlotCIcon will do the trick.
- >> john calhoun-
- >
- > nope. like i said in the message, i had been using release resource but
- > it still wasn't working. i kludged my way around it by quitting the
- > application after plotting a lot of icons (i only needed to see them for a
- > while while the app is in development). a more elegant solution remains
- > a mystery to me
-
- Whoops, sorry. It's DisposCIcon() that you need. So, GetCIcon(), PlotCIcon(),
- DisposCIcon().
-
- john calhoun-
-
-
- +++++++++++++++++++++++++++
-
- From: nextweek@reed.edu!nextweek.Reed.Edu!pcalahan (Patrick John Calahan)
- Date: 20 Jul 92 02:38:56 GMT
- Organization: Reed College, Portland, OR
-
- In article <1992Jul19.010403.41701@kuhub.cc.ukans.edu>
- ozma@kuhub.cc.ukans.edu writes:
- > In article <m0m8zd3-0006ChC@gluttony.reed.edu>,
- gluttony@reed.edu!gluttony.reed.edu!pcalahan (Patrick John Calahan)
- writes:
- > > In article <1992Jul16.234146.41639@kuhub.cc.ukans.edu>
- > > ozma@kuhub.cc.ukans.edu writes:
- > >> I believe ReleaseResource() after every PlotCIcon will do the trick.
- > >> john calhoun-
- > >
- > > nope. like i said in the message, i had been using release resource
- but
- > > it still wasn't working. i kludged my way around it by quitting the
- > > application after plotting a lot of icons (i only needed to see them
- for a
- > > while while the app is in development). a more elegant solution
- remains
- > > a mystery to me
- >
- > Whoops, sorry. It's DisposCIcon() that you need. So, GetCIcon(),
- PlotCIcon(),
- > DisposCIcon().
- >
- > john calhoun-
- >
- been trying that to...no go :) no matter to me anymore, though
-
- +++++++++++++++++++++++++++
-
- From: absurd@applelink.apple.com (Tim Dierks, software saboteur)
- Date: 29 Jul 92 00:09:18 GMT
- Organization: MacDTS Misfits
-
- In article <1992Jul16.234146.41639@kuhub.cc.ukans.edu>,
- ozma@kuhub.cc.ukans.edu wrote:
- >
- > In article <36915@unix.SRI.COM>, mxmora@unix.SRI.COM (Matt Mora) writes:
- > > In article <m0m7vfN-000FO0C@bagpipe.reed.edu> bagpipe@reed.edu!bagpipe.reed.edu!pcalahan (Patrick John Calahan) writes:
- > >
- > >>IMV says that you shouldn't call PlotCICon before each GetCIcon because
- > >>it overhead will build up in the resource map. Makes sense to me...that
- > >>seems to be happenening when my system crashes after plotting some number
- > >>of icons...
- >
- > > You could mark them purgeable. But I don't think that really works. I think
- > > there is a bug with cicns or something because I tried to get rid of the
- > > memory but it would still fill up the heap. I'm using ploticonid now
- > > (tech note #30x) and it works fine.
- >
- > I believe ReleaseResource() after every PlotCIcon will do the trick.
- >
- Actually, the appropriate call is DisposCIcon(), which will dispose of all
- the various handles associated with a color icon. ReleaseResource() would
- not release all the handles; in fact, I think it would be in error, because
- I'm pretty sure that a CIconHandle in memory is not a resource handle; it's
- constructed from one.
-
- Tim Dierks
- MacDTS, but I speak for the trees
-
- ---------------------------
-
- From: mar@ocf.berkeley.edu (Michael A. Ramirez)
- Subject: Powerbook Battery Question
- Date: 21 Jul 92 22:17:25 GMT
- Organization: U.C. Berkeley Open Computing Facility
-
-
-
- I am wondering how I can get rid of the dialog boxes warning me that the
- power is low on the Powerbooks. Are these dialog boxes in the ROM or
- in the System file? Any help or comments would be appreciated.
-
- Thanks.
-
- Michael
- - --
- - -----------------------------------------------------------------------------
- ___ _ ___ ___ _ ____ ____ ____ mar@ocf.berkeley.edu
- |__| |_| | | | | |___| |___ / When laws are outlawed then only
- | \ | | | | | | | \ |___ /___ outlaws will obey the law- Mondo 2000
-
- +++++++++++++++++++++++++++
-
- From: stevec@Apple.COM (Steve Christensen)
- Date: 25 Jul 92 02:30:12 GMT
- Organization: Apple Computer Inc., Cupertino, CA
-
- mar@ocf.berkeley.edu (Michael A. Ramirez) writes:
- >I am wondering how I can get rid of the dialog boxes warning me that the
- >power is low on the Powerbooks. Are these dialog boxes in the ROM or
- >in the System file? Any help or comments would be appreciated.
-
- I assume from your question that you don't mind if your PowerBook will
- suddenly go to sleep without notice in order to preserve the state of
- its memory (and thus your data)?
-
- OK, if so, you can find the strings it uses to warn you in the System File.
- If you remove them, you won't get any warnings, the PowerBook will just go
- to sleep...
-
- steve
-
- - --
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Steve Christensen Never hit a man with glasses.
- stevec@apple.com Hit him with a baseball bat.
-
- ---------------------------
-
- From: rla20@duts.ccc.amdahl.com (Roger Allen)
- Subject: Quick TCL gDesktop question
- Date: 21 Jul 92 21:24:46 GMT
- Organization: Amdahl Corporation, Sunnyvale CA
-
- Quickie:
-
- For multi-monitor systems, does gDesktop->bounds include the main device
- only or some rect that bounds all of the screens.
-
- In other words is gDesktop->bounds A or B. Where B is the main screen and
- C is another screen and A is the rect that bounds them.
-
- AAAAAAAAAAAAAAAAAAA
- ABBBBBBBB A
- AB B A
- AB .. B A
- AB \/ BCCCCCCCCCA
- AB BC CA
- ABBBBBBBBC CA
- A C CA
- A C CA
- A C CA
- A CCCCCCCCCA
- AAAAAAAAAAAAAAAAAAA
-
- Hope it takes less time to answer than it did to draw that.
-
-
- Roger
- - --
- > Roger Allen | <
- > Amdahl Computer Development | What are you looking here for? <
- > rla20@cd.amdahl.com | <
-
- +++++++++++++++++++++++++++
-
- From: k044477@hobbes.kzoo.edu (Jamie R. McCarthy)
- Date: 23 Jul 92 16:45:36 GMT
- Organization: Kalamazoo College
-
- rla20@DUTS.ccc.amdahl.com (Roger Allen) writes:
- >Quickie:
- >For multi-monitor systems, does gDesktop->bounds include the main device
- >only or some rect that bounds all of the screens.
-
- All the screens.
-
-
- This is despite the comment in ThC's TCL 1.1's CDesktop::IDesktop:
-
- /* Make the port rectangle coincide with the bounding box of */
- /* the gray region (entire screen excluding the menu bar). ... */
- grayRgn = GetGrayRgn();
- bounds = (**grayRgn).rgnBBox;
-
- The parenthetic should read "(all screens excluding the menu bar)".
-
-
- >Hope it takes less time to answer than it did to draw that.
-
- Probably... :-)
- - --
- Jamie McCarthy Internet: k044477@kzoo.edu AppleLink: j.mccarthy
- I'm having a lot of trouble seeing how a request that you "shut up" can be
- interpreted as "looking to other people for validation." - Tim Pierce
-
- ---------------------------
-
- From: tj@kona.cs.ucla.edu (Tom Johnson)
- Subject: Smooth Animation
- Date: 23 Jul 92 19:59:03 GMT
- Organization: UCLA Computer Science Department
-
-
- FAQ Alert! FAQ Alert! FAQ Alert!
-
- Could someone send me some sample code for doing smooth color
- animation that's compatible with all the different machines and
- accelerated/non-accelerated video cards out there?
-
- Or some discussion/archived c.s.m.p posts?
-
- I've seen so much of this in the past, but since my work never required
- any sort of animated graphics, I didn't save anything. And now.....
-
- Now I feel stupid for not saving them.
-
- Thanks-
- Tom
- - --
- Tom Johnson "They say Confucious does his crossword with a pen."
- tj@cs.ucla.edu -Tori Amos
-
- +++++++++++++++++++++++++++
-
- From: tj@kona.cs.ucla.edu (Tom Johnson)
- Organization: UCLA Computer Science Department
- Date: Fri, 31 Jul 92 20:57:37 GMT
-
- I'm thinking about writing a game, so I decided I'd play around a bit and
- try to get some nice fast and smooth animation running just to see how to
- do it. Nothing fancy, just a box bouncing around in a window on the screen.
- I've got the drawing sync'd to a VBL task and everything works great in a
- situation like this:
-
- do {
- DrawNextFrame();
- } while (!Button());
-
- of course. But when I put it into a real event loop:
- do {
- MainIdle();
- gotEvent = WaitNextEvent(everyEvent, &theEvent, 0,nil);
- if (gotEvent)
- HandleEvent(&theEvent);
- } while (gQuitApplication != true);
-
- I get all sorts of little starts/stops/pauses in the animation, as the mac
- gives time to background processes. And it's certainly not acceptable for
- a fast arcade-style game.
-
- How do other game authors handle it? Do you not give time to bkgnd processes?
- Just let downloads timeout? Or is there some simple idea that's gone by
- me completely?
-
-
- Question 2: I've given up on getting enough speed from CopyBits and have
- decided that I'm willing to take a few risks and write directly to the
- screen. I found the sample code in the FAQ for setting pixels. Does anyone
- have some utility routines they might be willing to share to handle other
- tasks? (ie drawing Icl's, etc...).
-
- This is just a little throw away freeware
- game, so I'm trying to get as much done as I can as quickly as possible. Has
- anyone ever written a sample arcade game and given away the source? Something
- I could base mine upon?
-
- Thanks-
- Tom
-
- - --
- Tom Johnson "They say Confucious does his crossword with a pen."
- tj@cs.ucla.edu -Tori Amos
-
- +++++++++++++++++++++++++++
-
- From: mspace@netcom.com (Brian Hall)
- Date: Sat, 01 Aug 92 07:03:09 GMT
- Organization: Netcom - Online Communication Services (408 241-9760 guest)
-
- tj@kona.cs.ucla.edu (Tom Johnson) writes:
-
- >I'm thinking about writing a game, so I decided I'd play around a bit and
- >try to get some nice fast and smooth animation running just to see how to
- >do it. Nothing fancy, just a box bouncing around in a window on the screen.
- >I've got the drawing sync'd to a VBL task and everything works great in a
- >situation like this:
-
- > do {
- > DrawNextFrame();
- > } while (!Button());
-
- >of course. But when I put it into a real event loop:
- > do {
- > MainIdle();
- > gotEvent = WaitNextEvent(everyEvent, &theEvent, 0,nil);
- > if (gotEvent)
- > HandleEvent(&theEvent);
- > } while (gQuitApplication != true);
-
- >I get all sorts of little starts/stops/pauses in the animation, as the mac
- >gives time to background processes. And it's certainly not acceptable for
- >a fast arcade-style game.
-
- Instead of calling WNE for each pass through the loop, why not try calling
- it once every few ticks. Perhaps one call every 10 ticks. You could
- vary the number depending on how friendly you want to be.
-
- A friend of mine did this in a database program he was working on where
- it called WNE during long processes, and found that by calling WNE once
- every so often instead of once per pass, he was able to more than double
- the time to sort the database.
-
- - --
-
- \ | / | Brian Hall mspace@netcom.com
- - : - | Mark/Space Softworks Applelink: markspace
- /|\ | America Online: MarkSpace
- |-+-| |
- /-\|/-\ | People don't kill people, toasters kill people.
-
- ---------------------------
-
- From: mmigdol@ccwf.cc.utexas.edu (michael a migdol)
- Subject: Using PostHighLevelEvents to send low level (KeyPressed) events
- Date: 24 Jul 92 14:31:06 GMT
- Organization: The University of Texas at Austin, Austin TX
-
- According to IM VI, p. 5-18, "Your application can both send and receive high-
- level events, but it generally only receives low-level events and should not
- send them."
-
- So, this implies that I *can* send KeyPressed events to other applications.
- (Even though I "shouldn't", I want to. I really do! :) )
-
- Anyways, Apple certainly doesn't seem to encourage this, and I'm about to try
- this out myself, but am I supposed to use PostHighLevelEvents with theEvent.what
- set to Keypressed (or whatever) to do this? Am I going to hit any problems
- later on? Does the application I'm sending to have to "AcceptHighLevelEvents"
- to receive low level events sent this way?
-
- Thanks in advance, and smile - it's FRIDAY!
- - -Michael
-
- +++++++++++++++++++++++++++
-
- From: smoke@well.sf.ca.us (Nicholas Jackiw)
- Organization: Whole Earth 'Lectronic Link
- Date: Fri, 24 Jul 1992 16:04:10 GMT
-
- In article <76508@ut-emx.uucp> mmigdol@ccwf.cc.utexas.edu (michael a migdol) writes:
- >According to IM VI, p. 5-18, "Your application can both send and receive high-
- >level events, but it generally only receives low-level events and should not
- >send them."
- >
- >So, this implies that I *can* send KeyPressed events to other applications.
- >(Even though I "shouldn't", I want to. I really do! :) )
-
- That's right; you can and "shouldn't." Remember, however, that it's *your*
- Macintosh and you can do what you damn well like with it.
-
- >
- >Anyways, Apple certainly doesn't seem to encourage this, and I'm about to try
- >this out myself, but am I supposed to use PostHighLevelEvents with theEvent.what
- >set to Keypressed (or whatever) to do this? Am I going to hit any problems
- >later on? Does the application I'm sending to have to "AcceptHighLevelEvents"
- >to receive low level events sent this way?
-
- No, PostHighLevelEvents won't work for this; all high-level events are of
- the same low-level event type. Nor do you need AcceptHighLevelEvents; this
- will simply add unnecessary launch-time overhead.
-
- I believe that any low-level event gets sent to the event handler of the
- foremost application. This means you'll need to have your receiver in
- front. (See the Process Manager in System 7 for how to do this automatically,
- otherwise just bring it to the front with the multifinder menu after
- launching the sender.) Then, call PostEvent from your sender with
- the appropriate keydowns.
-
- [Actually, I think you should use PPostEvent, which will return to you
- a pointer to the event that will be shipped the frontapp. You want this
- pointer if you intend to do any preprocessing of the event record, such
- as clearing its modifier keys or setting the "where" field to a mouse
- location of your choice.]
-
-
-
- - --
- --- * ---
- Nick Jackiw Smoke@well.sf.ca.us | Jackiw@cs.swarthmore.edu
- Key Curriculum Press, Inc. Applelink:KEY.EDUSOFT | (510) 548-2304
- --- * ---
-
- +++++++++++++++++++++++++++
-
- From: walkerj@math.scarolina.edu (Jim Walker)
- Date: 24 Jul 92 17:35:37 GMT
- Organization: USC Department of Computer Science
-
- To post low-level events, use PPostEvent. It is documented in IM IV, but
- was omitted from the index. I think it's in the chapter on the OS Event
- Manager. The advantage of PPostEvent over PostEvent is that the former
- allows you to set the modifiers, location, and time as well as the message.
-
-
- - --
-
- -- Jim Walker USC Dept. of Math. walkerj@math.scarolina.edu
-
- ---------------------------
-
- From: fsmah1@acad3.alaska.edu (Mike Hageland)
- Subject: Radio buttons
- Date: 27 Jul 92 03:51:45 GMT
- Organization: University of Alaska Fairbanks
-
- I have a very simple little problem with what seems to be a complicated
- solution. Look at this diagram and pretend the X represents where I
- want a radio button.
-
- X Title | Title X
- X Title | Title X
- X Title | Title X
-
- Personally I think this looks kinda neat. I would like to do something
- like this. Now this is no problem, I can simply draw the titles in and
- then place in the radio buttons. However, then you can't simply click
- onto the title like you can with most radio buttons. It seems that the
- radio button will only put the title to the right of the radio button.
-
- The way I can think of to do this is to create another simple button over the
- titles on the right side and deal with changing the radio buttons around
- when it is pressed.
-
- Can anybody think of a cleaner way to do this? Is there a hiden way to
- make a radio button have a title on the left?
-
- +++++++++++++++++++++++++++
-
- From: ericsc@microsoft.com (Eric Schlegel)
- Date: 29 Jul 92 19:58:07 GMT
- Organization: Microsoft Corporation
-
- In article <1992Jul26.195145.1@acad3.alaska.edu> fsmah1@acad3.alaska.edu (Mike Hageland) writes:
- >I have a very simple little problem with what seems to be a complicated
- >solution. Look at this diagram and pretend the X represents where I
- >want a radio button.
- >
- > X Title | Title X
- > X Title | Title X
- > X Title | Title X
- >
- >Personally I think this looks kinda neat. I would like to do something
- >like this. Now this is no problem, I can simply draw the titles in and
- >then place in the radio buttons. However, then you can't simply click
- >onto the title like you can with most radio buttons. It seems that the
- >radio button will only put the title to the right of the radio button.
- >
- >Is there a hidden way to make a radio button have a title on the left?
-
- You need to set the system justification to teFlushRight (-1) before
- drawing the right-hand column of radio buttons. You can do this with the
- Script Manager trap _SetSysJust:
- SetSysJust(teFlushRight);
- Don't forget to save the previous justification using _GetSysJust before
- changing it, and restore it afterwards.
-
- If you're doing this in a window of your own creation, you can just
- call _SetSysJust and then _Draw1Control to draw the right-hand radio buttons.
- If your radio buttons are in a Dialog Manager dialog you may need to use
- a filter proc that catches update events and does the updating itself,
- using _SetSysJust and _Draw1Control as needed, instead of letting the Dialog
- Manager draw the controls.
-
- For more information, see Inside Mac vol. 5, pg. 301, "Writing Direction."
-
- - -eric
- - -------
- My opinions, not Microsoft's.
-
- ---------------------------
-
- From: kaas@cc.ruu.nl (Dick Kaas)
- Subject: menubar in dialogs
- Date: 28 Jul 92 13:27:28 GMT
- Organization: -
-
-
- I'm planning to write a TCL pane for a menu-bar.
-
- Is there a simple way to implement a menubar into dialogs (like WP and
- superboomerang) without having to write a complete menu package by
- yourself?
-
- I have looked at the low memory globals, such as MenuBarHook etc. None of
- these seem useful.
-
- Dick kaas.
-
- +++++++++++++++++++++++++++
-
- From: keith@taligent.com (Keith Rollin)
- Date: 29 Jul 92 08:17:31 GMT
- Organization: Taligent
-
- In article <kaas-280792151810@jojo.cc.ruu.nl>, kaas@cc.ruu.nl (Dick Kaas)
- writes:
- >
- > I'm planning to write a TCL pane for a menu-bar.
- >
- > Is there a simple way to implement a menubar into dialogs (like WP and
- > superboomerang) without having to write a complete menu package by
- > yourself?
- >
- > I have looked at the low memory globals, such as MenuBarHook etc. None of
- > these seem useful.
- >
-
- I did one of these. I wouldn't consider the approach I took to be "simple."
- Although I wrote the bulk of it in a couple of nights, they were long nights. I
- had to re-implement and wrap up a lot of stuff. My first attempt that tried
- setting the origin of the window manager port at strategic times didn't work
- because of a bug in System 7.0's background saving and restoring routines.
-
- I did it as a control to make it easy for others to use. It's included below.
-
- How to use: create a control item in your DITL, and specify the CDEF shown
- below. When the user clicks on the item, the dialog manager will call
- TrackControl. If you are writing a TCL pane, then call TrackControl yourself.
- The control will track the menus and leave the chosen item in contrlValue, so
- all you have to do is call GetCtlValue to get the chosen menu item.
-
- If you want to manipulate the menubar, use one of the macros starting with a "Z"
- included below. Those macros will call the CDEF directly with a custom message
- number. Please note that for the CallIt macro to work, the CDEF must be marked
- as locked. If you don't want to lock your CDEF, then you'll need a more
- elaborate way to call the CDEF than just dereferencing the handle and jumping.
- As an example of what you might need, I've included a commented-out function at
- the end of this posting that calls the standard MBDF directly.
-
- A note: pay no attention to the UseGlobals and DoneWithGlobals stuff. That's for
- an MPW package that allows globals in standalone code. If you are using THINK C,
- don't worry about it. If you are using MPW, use the techniques shown in Technote
- #256.
-
- (BTW: as you'll see below, MenubarHook _was_ useful!)
-
- As a final note, I found it useful to write a wrapper for the standard MDEF.
- Because the below CDEF essentially works by using popup menus, you need to have
- fine control over where the popup menus show up. The standard MBDF will try to
- position popup menus so that as much of them will appear on the screen as
- possible. However, we don't want that with our menubar CDEF; we want to the top
- of the menu to be right below the menubar. Therefore, I wrap up the standard
- MDEF with one of my own that first calls the standard MDEF, and then checks to
- see if the message handled was mPopUpMsg. If so, the top of the menu is adjusted
- by executing "menuRect->top = *itemID;".
-
- Sorry for the lack of any comments in the source code...
-
- - -------------
- MenubarCDEF.h
- - -------------
-
- #ifndef THINK_C
- #include <Controls.h>
- #endif
-
- #define kStayPutMDEF 90
-
- #define clearMenuBar 128
- #define deleteMenu 129 // param = ID of menu to remove
- #define drawMenuBar 130
- #define flashMenuBar 131 // param = ID of menu to flash
- #define getMenuBar 132 // result = handle to custom data
- #define getMHandle 133 // param = menu ID, result = menuHandle
- #define hiliteMenu 134 // param = ID of menu to hilite
- #define insertMenu 135 // param = menuHandle, varCode = before menu ID
- #define menuKey 136 // param = char, result = same as MenuKey
- #define menuSelect 137 // param = startPt, result = same as MenuSelect
- #define setMenuBar 138 // param = result from getMenuBar
-
- typedef pascal long (*CDEFProc)(short varCode, ControlHandle theControl,
- short msg, long param);
-
- #define CallIt(ctl) ((CDEFProc) *((**ctl).contrlDefProc))
-
- #define ZClearMenuBar(ctl) CallIt(ctl)(0, ctl, clearMenuBar, 0)
- #define ZDeleteMenu(ctl, menuID) CallIt(ctl)(0, ctl, deleteMenu, menuID)
- #define ZDrawMenuBar(ctl) CallIt(ctl)(0, ctl, drawMenuBar, 0)
- #define ZFlashMenuBar(ctl, menuID) CallIt(ctl)(0, ctl, flashMenuBar, menuID)
- #define ZGetMenuBar(ctl) (Handle) CallIt(ctl)(0, ctl, getMenuBar, 0)
- #define ZGetMHandle(ctl, menuID) (MenuHandle) CallIt(ctl)(0, ctl, getMHandle,
- menuID)
- #define ZHiliteMenu(ctl, menuID) CallIt(ctl)(0, ctl, hiliteMenu, 0)
- #define ZInsertMenu(ctl, mh, id) CallIt(ctl)(id, ctl, insertMenu, mh)
- #define ZMenuKey(ctl, key) CallIt(ctl)(0, ctl, menuKey, key)
- #define ZMenuSelect(ctl, startPt) CallIt(ctl)(0, ctl, menuSelect, startPt)
- #define ZSetMenuBar(ctl, mbar) CallIt(ctl)(0, ctl, setMenuBar, mbar)
-
-
-
- - -------------
- MenubarCDEF.c
- - -------------
-
-
- /*
- To do:
-
- % Support hierarchicals
- % Support color
- */
-
- #include "MetaGlobal.h"
- #include "MenubarCDEF.h"
-
- #ifdef THINK_C
- #include <SetUpA4.h>
- Ptr GetA0(void) = { 0x2008 };
- #else
- #include <Types.h>
- #include <Memory.h>
- #include <Menus.h>
- #include <OSEvents.h> // For EvQPtr
- #include <Resources.h> // For GetResource
- #include <Script.h> // For GetMBarHeight
- #include <ToolUtils.h> // For HiWord, LoWord
- #include <Windows.h> // we return inMenubar as our part
- #include "SAGlobals.h"
-
- #define MenuHook (*(ProcPtr*) 0xA30)
- #define MenuList (*(Handle*) 0xA1C)
- #endif
-
- #define NIL NULL
- #define kTopMargin 1
- #define kBottomMargin 1
- #define kTextMargin 8
-
-
- typedef struct {
- MenuHandle menu;
- short menuLeft;
- } MenuRec, *MenuRecPtr;
-
-
- typedef struct {
- MenuHandle menu;
- short reserved;
- } HMenuRec, *HMenuRecPtr;
-
-
- typedef struct {
- short lastMenu;
- short lastRight;
- short mbResID;
- MenuRec menus[1];
- // short lastHMenu;
- // PixMapHandle menuTitleSave;
- // MenuRec hmenus[1];
- } MenuBar, *MenuBarPtr, **MenuBarHdl;
-
-
- ProcPtr gOldMenuHook;
- ControlHandle gControl;
- MenuBarHdl gMenuList;
- short gTheMenu; // _Index_ of currently hilighted menu
- short gNormalHeight;
- FontInfo gFontInfo;
- short gBaseline;
-
-
- pascal long main(short varCode, ControlHandle theControl, short msg, long
- param);
-
- void DrawMyControl(short part);
- short TestMyControl(Point location);
- void InitMyControl(void);
- void DisposeMyControl(void);
-
- void DoClearMenuBar(void);
- void DoDeleteMenu(short menuID);
- void DoDrawMenuBar(void);
- void DoFlashMenuBar(short menuID);
- MenuBarHdl DoGetMenuBar(void);
- MenuHandle DoGetMHandle(short menuID);
- void DoHiliteMenu(short menuID);
- void DoInsertMenu(MenuHandle menu, short before);
- long DoMenuKey(char theKey);
- long DoMenuSelect(Point startPt);
- void DoSetMenuBar(MenuBarHdl menuBar);
-
- void DrawMenuTitle(short menuIndex);
- short FindHitMenu(Point location); // returns menuIndex (or -1)
- short GetFreeHMenuID(void);
- Rect GetHitRect(short menuIndex);
- Rect GetInvertRect(short menuIndex);
- short GetMenuCount(void);
- MenuHandle GetNthMenu(short index);
- Point GetTitleLocation(short menuIndex);
- short IDToIndex(short);
- short IndexToID(short);
- void MyMenuHook(void);
- void SwapMenuBars(void);
-
- //--------------------------------------------------------------------------------
-
- pascal long main(short varCode, ControlHandle theControl, short msg, long param)
- {
- long result;
- Ptr oldA5;
- char oldState;
- Handle ourHandle;
- Ptr ourPtr;
-
- ourPtr = GetA0();
-
- #ifdef THINK_C
- RememberA0();
- SetUpA4();
- #else
- oldA5 = UseGlobals();
- #endif
-
- ourHandle = RecoverHandle(ourPtr);
- oldState = HGetState(ourHandle);
- HLock(ourHandle);
-
- result = 0;
- gControl = theControl;
- GetFontInfo(&gFontInfo);
- gBaseline = kTopMargin + gFontInfo.leading + gFontInfo.ascent;
-
- if (msg < 128) {
- switch (msg) {
- case drawCntl:
- DrawMyControl((short) param);
- break;
- case testCntl:
- result = TestMyControl(*(Point*) ¶m);
- break;
- case initCntl:
- InitMyControl();
- break;
- case dispCntl:
- DisposeMyControl();
- break;
- case calcCntlRgn:
- case calcThumbRgn:
- RectRgn((RgnHandle) param, &(**gControl).contrlRect);
- result = 1;
- break;
- }
- } else {
- switch (msg) {
- case clearMenuBar:
- DoClearMenuBar();
- break;
- case deleteMenu:
- DoDeleteMenu((short) param);
- break;
- case drawMenuBar:
- DoDrawMenuBar();
- break;
- case flashMenuBar:
- DoFlashMenuBar((short) param);
- break;
- case getMenuBar:
- result = (long) DoGetMenuBar();
- break;
- case getMHandle:
- result = (long) DoGetMHandle((short) param);
- break;
- case hiliteMenu:
- DoHiliteMenu((short) param);
- break;
- case insertMenu:
- DoInsertMenu((MenuHandle) param, varCode);
- break;
- case menuKey:
- result = DoMenuKey((char) param);
- break;
- case menuSelect:
- result = DoMenuSelect(*(Point*) ¶m);
- break;
- case setMenuBar:
- DoSetMenuBar((MenuBarHdl) param);
- break;
- }
- }
-
- #ifdef THINK_C
- RestoreA4();
- #else
- DoneWithGlobals(oldA5);
- #endif
-
- HSetState(ourHandle, oldState);
-
- return result;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DrawMyControl(short part)
- {
- #pragma unused (part)
-
- if ((**gControl).contrlVis != false) {
- DoDrawMenuBar();
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- short TestMyControl(Point location)
- {
- short hitPart;
-
- hitPart = 0;
- if (FindHitMenu(location) >= 0) {
- hitPart = inMenuBar;
- if (Button()) {
- DoMenuSelect(location);
- if ((**gControl).contrlValue == 0) {
- hitPart = 0;
- }
- }
- }
-
- return hitPart;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void InitMyControl()
- {
- Handle menuBar;
-
- gOldMenuHook = NIL;
- gMenuList = NIL;
- gTheMenu = -1;
- gNormalHeight = GetMBarHeight();
- (**gControl).contrlRect.bottom = (**gControl).contrlRect.top + gBaseline
- + gFontInfo.descent + gFontInfo.leading + kBottomMargin;
-
- GetMBarHeight() = 0;
- menuBar = GetNewMBar((**gControl).contrlMin);
- if (menuBar != NIL) {
- gMenuList = (MenuBarHdl) menuBar;
- } else {
- menuBar = GetMenuBar();
- ClearMenuBar();
- gMenuList = (MenuBarHdl) GetMenuBar();
- SetMenuBar(menuBar);
- DisposeHandle(menuBar);
- }
- GetMBarHeight() = gNormalHeight;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DisposeMyControl()
- {
- DisposeHandle((Handle) gMenuList);
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoClearMenuBar()
- {
- SwapMenuBars();
- ClearMenuBar();
- SwapMenuBars();
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoDeleteMenu(short menuID)
- {
- if (IndexToID(gTheMenu) == menuID)
- gTheMenu = -1;
-
- SwapMenuBars();
- DeleteMenu(menuID);
- SwapMenuBars();
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoDrawMenuBar()
- {
- Rect frame;
- short loop;
-
- PenNormal();
- frame = (**gControl).contrlRect;
- FrameRect(&frame);
-
- gTheMenu = -1;
- for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
- DrawMenuTitle(loop);
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoFlashMenuBar(short menuID)
- {
- Rect bounds;
-
- if (menuID != 0)
- DoHiliteMenu(menuID);
- else {
- bounds = (**gControl).contrlRect;
- InsetRect(&bounds, 1, 1);
- InvertRect(&bounds);
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- MenuBarHdl DoGetMenuBar()
- {
- return gMenuList;
- }
-
-
- //--------------------------------------------------------------------------------
-
- MenuHandle DoGetMHandle(short menuID)
- {
- short menuIndex;
-
- menuIndex = IDToIndex(menuID);
- if (menuIndex >= 0)
- return GetNthMenu(menuIndex);
- else
- return NIL;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoHiliteMenu(short menuID)
- {
- short menuIndex;
- Rect invertRect;
-
- menuIndex = IDToIndex(menuID);
- if (menuIndex != gTheMenu) {
- if (menuIndex >= 0) {
- invertRect = GetInvertRect(menuIndex);
- InvertRect(&invertRect);
- }
- gTheMenu = menuIndex;
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoInsertMenu(MenuHandle menu, short before)
- {
- SwapMenuBars();
- InsertMenu(menu, before);
- SwapMenuBars();
- }
-
-
- //--------------------------------------------------------------------------------
-
- long DoMenuKey(char theKey)
- {
- char upperKey[2];
- short loop;
- MenuHandle menu;
- short mItems;
- short menuItem;
- short key;
-
- upperKey[0] = 1;
- upperKey[1] = theKey;
- UprString((StringPtr) &upperKey, true);
-
- for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
- menu = GetNthMenu(loop);
- mItems = CountMItems(menu);
- for (menuItem = 1; menuItem <= mItems; menuItem++) {
- if (menuItem > 31 || (((**menu).enableFlags & (1 << menuItem)) != 0)) {
- GetItemCmd(menu, menuItem, &key);
- if (key == upperKey[1]) {
- return ((long) (**menu).menuID << 16) + menuItem;
- }
- }
- }
- }
-
- return 0;
- }
-
-
- //--------------------------------------------------------------------------------
-
- long DoMenuSelect(Point startPt)
- {
- #pragma unused (startPt)
-
- Point currentLocation;
- short oldMenuIndex;
- short newMenuIndex;
- Rect invertRect;
- Point where;
- MenuHandle menu;
- long menuAndItem;
- short oldMenuID;
- Handle myMDEF;
-
- menuAndItem = 0;
- while (Button()) {
- GetMouse(¤tLocation);
- oldMenuIndex = gTheMenu;
- newMenuIndex = FindHitMenu(currentLocation);
- if (oldMenuIndex != newMenuIndex) {
- gTheMenu = newMenuIndex;
- DrawMenuTitle(oldMenuIndex);
- if (newMenuIndex >= 0) {
- DrawMenuTitle(newMenuIndex);
-
- invertRect = GetInvertRect(newMenuIndex);
- where.v = invertRect.bottom + 1;
- where.h = invertRect.left + 1;
- LocalToGlobal(&where);
-
- gOldMenuHook = MenuHook;
- MenuHook = (ProcPtr) MyMenuHook;
-
- menu = GetNthMenu(newMenuIndex);
-
- oldMenuID = (**menu).menuID;
- (**menu).menuID = GetFreeHMenuID();
-
- myMDEF = GetResource('MDEF', kStayPutMDEF);
- if (myMDEF != NIL) {
- (**(StdHeaderHdl) myMDEF).refCon = (long) (**menu).menuProc;
- (**menu).menuProc = myMDEF;
- }
-
- InsertMenu(menu, hierMenu);
- menuAndItem = PopUpMenuSelect(menu, where.v, where.h, 1);
- DeleteMenu((**menu).menuID);
-
- (**menu).menuID = oldMenuID;
-
- if (myMDEF != NIL) {
- (**menu).menuProc = (Handle) (**(StdHeaderHdl) myMDEF).refCon;
- (**(StdHeaderHdl) myMDEF).refCon = (long) NIL;
- }
-
- MenuHook = gOldMenuHook;
-
- if (HiWord(menuAndItem) != 0)
- menuAndItem = ((long) oldMenuID << 16) + (short) menuAndItem;
-
- (**gControl).contrlValue = HiWord(menuAndItem);
- (**gControl).contrlMax = LoWord(menuAndItem);
- }
- }
- }
-
- if (gTheMenu != -1) {
- oldMenuIndex = gTheMenu;
- gTheMenu = -1;
- DrawMenuTitle(oldMenuIndex);
- }
-
- return menuAndItem;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoSetMenuBar(MenuBarHdl menuBar)
- {
- DisposeHandle((Handle) gMenuList);
- gMenuList = menuBar;
- DoDrawMenuBar();
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DrawMenuTitle(short menuIndex)
- {
- Rect invertRect;
- Point titleLocation;
- MenuHandle menu;
-
- if ((menuIndex >= 0) && (menuIndex < GetMenuCount())) {
-
- invertRect = GetInvertRect(menuIndex);
- EraseRect(&invertRect);
-
- menu = GetNthMenu(menuIndex);
- if ((((**menu).enableFlags & 1) == 0) || ((**gControl).contrlHilite == 255))
- TextMode(grayishTextOr);
- else
- TextMode(srcOr);
-
- titleLocation = GetTitleLocation(menuIndex);
- MoveTo(titleLocation.h, titleLocation.v);
- HLock((Handle) menu);
- DrawString((**menu).menuData);
- HUnlock((Handle) menu);
-
- if (gTheMenu == menuIndex)
- InvertRect(&invertRect);
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- short FindHitMenu(Point location)
- {
- short loop;
- Rect hitRect;
-
- for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
- hitRect = GetHitRect(loop);
- if (PtInRect(location, &hitRect)) {
- break;
- }
- }
-
- return loop; // returns -1 if no hit
- }
-
-
- //--------------------------------------------------------------------------------
-
- short GetFreeHMenuID(void)
- {
- short index;
-
- for (index = 235-20; index > 0; index--) {
- if (GetMHandle(index) == NIL)
- return index;
- }
- return -1;
- }
-
-
- //--------------------------------------------------------------------------------
-
- Rect GetHitRect(short menuIndex)
- {
- Rect bounds;
- RectPtr rectPtr;
- MenuBarPtr menuBarPtr;
-
- rectPtr = &(**gControl).contrlRect;
- menuBarPtr = *gMenuList;
-
- bounds.top = rectPtr->top + 1;
- bounds.bottom = rectPtr->bottom - 1;
- bounds.left = rectPtr->left + menuBarPtr->menus[menuIndex].menuLeft;
- menuIndex++;
- bounds.right = rectPtr->left + ((menuIndex < GetMenuCount())
- ? menuBarPtr->menus[menuIndex].menuLeft
- : menuBarPtr->lastRight);
-
- return bounds;
- }
-
-
- //--------------------------------------------------------------------------------
-
- Rect GetInvertRect(short menuIndex)
- {
- Rect bounds;
-
- bounds = GetHitRect(menuIndex);
- bounds.left--;
- bounds.right += 4;
- return bounds;
- }
-
-
- //--------------------------------------------------------------------------------
-
- short GetMenuCount()
- {
- return (**gMenuList).lastMenu / (short) sizeof(MenuRec);
- }
-
-
- //--------------------------------------------------------------------------------
-
- MenuHandle GetNthMenu(short index)
- {
- return (**gMenuList).menus[index].menu;
- }
-
-
- //--------------------------------------------------------------------------------
-
- Point GetTitleLocation(short menuIndex)
- {
- Point result;
-
- result.h = (**gMenuList).menus[menuIndex].menuLeft + kTextMargin;
- result.v = (**gControl).contrlRect.top + gBaseline;
-
- return result;
- }
-
-
- //--------------------------------------------------------------------------------
-
- short IDToIndex(short menuID)
- {
- short loop;
-
- for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
- if ((**GetNthMenu(loop)).menuID == menuID)
- break;
- }
- return loop;
- }
-
-
- //--------------------------------------------------------------------------------
-
- short IndexToID(short menuIndex)
- {
- if ((menuIndex >= 0) && (menuIndex < GetMenuCount()))
- return (**GetNthMenu(menuIndex)).menuID;
- else
- return 0;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void MyMenuHook()
- {
- typedef void (*MenuHookProc)(void);
-
- GrafPtr oldPort;
- Point mouseLocation;
- short hitMenu;
- Ptr oldA5;
-
- #ifdef THINK_C
- SetUpA4();
- #else
- oldA5 = UseGlobals();
- #endif
-
- if (gOldMenuHook != NIL)
- ((MenuHookProc) gOldMenuHook)();
-
- GetPort(&oldPort);
- SetPort((**gControl).contrlOwner);
- GetMouse(&mouseLocation);
- hitMenu = FindHitMenu(mouseLocation);
- if ((hitMenu >= 0) && (hitMenu != gTheMenu)) {
- PostEvent(mouseUp, 0);
- }
- SetPort(oldPort);
-
- #ifdef THINK_C
- RestoreA4();
- #else
- DoneWithGlobals(oldA5);
- #endif
- }
-
-
- //--------------------------------------------------------------------------------
-
- void SwapMenuBars()
- {
- MenuBarHdl oldMenuBar;
-
- oldMenuBar = (MenuBarHdl) MenuList;
- MenuList = (Handle) gMenuList;
- gMenuList = oldMenuBar;
- }
-
-
-
-
-
- #if 0
-
- void CalcMenuPositions(short index);
- long CallMBDF(short message, short param1, long param2);
-
- //--------------------------------------------------------------------------------
-
- void CalcMenuPositions(short index)
- {
- SwapMenuBars();
- CallMBDF(2, 0, (index+1) * 6);
- SwapMenuBars();
- }
-
-
- //--------------------------------------------------------------------------------
-
- long CallMBDF(short message, short param1, long param2)
- {
- typedef pascal long (*MBDFProc)(short selector, short message, short
- parameter1,
- long parameter2);
- Handle mbdfHandle;
- short mbResID;
- short resID;
- short mbVariant;
- char oldState;
- long result;
-
- mbResID = (**gMenuList).mbResID;
- resID = mbResID >> 3;
- mbVariant = mbResID & 0x0007;
- mbdfHandle = GetResource('MBDF', resID);
- if (mbdfHandle != NIL) {
- if (*mbdfHandle == NIL) {
- LoadResource(mbdfHandle);
- }
- if (*mbdfHandle != NIL) {
-
- oldState = HGetState(mbdfHandle);
- HLock(mbdfHandle);
- result = ((MBDFProc) *mbdfHandle)(mbVariant, message, param1, param2);
- HSetState(mbdfHandle, oldState);
- return result;
- }
- }
-
- SysError(dsMBarNFnd);
- }
- #endif
-
-
- - --
- Keith Rollin
- Phantom Programmer
- Taligent, Inc.
-
- ---------------------------
-
- End of C.S.M.P. Digest
- **********************
-